//                 _              
//                | |             
//   __ _ _ __ ___| |__ __  _____ 
//  / _` | '__/ __| '_ \\ \/ / __|
// | (_| | | | (__| | | |>  <\__ \
//  \__,_|_|  \___|_| |_/_/\_\___/
//                                
// Copyright 2010 Scott Dixon http://www.archxs.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package com.archxs.commons;

import java.lang.reflect.Constructor;

/**
 * 
 */
final class VariantObjectCacheFactory {

    private static final VariantObjectCache m_cache;
    
    static {
        m_cache = createNewInstance();
    }
    
    static VariantObjectCache getInstance() {
        return m_cache;
    }
    
    private VariantObjectCacheFactory() {
        // Cannot instantiate this class.
        throw new UnsupportedOperationException("The VariantObjectCacheFactory " +
            "object cannot be instatiated. It is strictly a singleton object that " +
            "operates within the static scope of its class loader.");
    }
    
    private static VariantObjectCache createNewInstance() {
        VariantObjectCache cacheImpl = null;
        boolean debug = false;
        try {
            debug = Boolean.getBoolean(VariantObjectCache.CACHE_DEBUG_PROPERTY);
        } catch (final SecurityException e) {
            // Cannot enable object cache debugging.
        }
        
        try {
            final String implName = System.getProperty(VariantObjectCache.CACHE_IMPL_PROPERTY);
            if (null != implName && implName.length() > 0) {
                try {
                    @SuppressWarnings("unchecked")
                    final Class<? extends VariantObjectCache> cacheClass = (Class<? extends VariantObjectCache>) Class.forName(implName);
                    try {
                        // We get a declared constructor but don't setAccessible on it
                        // to get better information from the exceptions. If the constructor
                        // is not visible we'll still get a reference to it (i.e. we
                        // won't get a confusing "doesn't exist" exception) but
                        // we'll have a nice "illegal access" exception to tell us about
                        // the visibility problems.
                        final Constructor<? extends VariantObjectCache> defaultConstructor = cacheClass.getDeclaredConstructor();
                        cacheImpl = defaultConstructor.newInstance();
                    } catch (final Exception e) {
                        if (debug) {
                            e.printStackTrace();
                        }
                    }
                } catch (final ClassNotFoundException e) {
                    if (debug) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (final SecurityException e) {
            // Security manager didn't let us access that key.
            if (debug) {
                e.printStackTrace();
            }
        }
        if (null == cacheImpl) {
            // We link directly to the default symbol to ensure that any code obfuscation
            // done on this module doesn't render it useless.
            cacheImpl = new VariantObjectCacheDefault();
        }
        return cacheImpl;
    }
}
